package hander

import (
	"context"
	"fmt"
	"math"
	"time"

	"github.com/beego/beego/v2/core/logs"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"2106a-zg5/demo/user/user_srv/global"
	"2106a-zg5/demo/user/user_srv/models"
	"2106a-zg5/demo/user/user_srv/proto"
	"2106a-zg5/demo/user/user_srv/utils"
)

type UserService struct {
	proto.UnimplementedUserServiceServer
}

// UserLogin 用户登录
func (c *UserService) UserLogin(ctx context.Context, req *proto.UserLoginReq) (*proto.UserLoginResp, error) {
	var u models.User
	res := global.DB.Table("user").Where("username=?", req.Username).First(&u)
	if res.Error != nil {
		return nil, status.Errorf(codes.Unimplemented, "用户不存在，请先注册！！！")
	}
	if !utils.CheckPassword(req.Password, u.Password) {
		return nil, status.Errorf(codes.Unimplemented, "密码错误！！！")
	}
	zap.S().Info("登录成功")

	data := modelResponse(u)
	return &proto.UserLoginResp{
		User: data,
		Code: 1,
	}, nil
}

// UserReg 用户注册
func (c *UserService) UserReg(ctx context.Context, req *proto.UserRegReq) (*proto.UserRegResp, error) {
	logs.Info("我就来了哦")
	var u models.User
	res := global.DB.Table("user").Where("username=?", req.Username).First(&u)
	if res.Error == nil {
		return nil, status.Errorf(codes.Unimplemented, "用户已存在！！！")
	}
	pwd := utils.GetPassword(req.Password)
	u.Username = req.Username
	u.Password = pwd
	u.Email = req.Email
	u.Mobile = req.Mobile
	u.UserBalance = 0
	u.CreatedAt = time.Now().Format(time.DateTime)
	u.UpdatedAt = time.Now().Format(time.DateTime)
	res = global.DB.Table("user").Create(&u)
	if res.Error != nil {
		return nil, status.Errorf(codes.Unimplemented, "注册失败!!!")
	}
	data := modelResponse(u)

	return &proto.UserRegResp{
		Code: 1,
		User: data,
	}, nil
}

// UserUpPwd 用户修改密码
func (c *UserService) UserUpPwd(ctx context.Context, req *proto.UserUpPwdReq) (*proto.UserUpPwdResp, error) {

	pwd := utils.GetPassword(req.Password)

	res := global.DB.Table("user").Where("id=?", req.Id).Update("password=?", pwd)
	if res.Error != nil {
		return nil, status.Errorf(codes.Unimplemented, "密码修改失败!!!")
	}
	return &proto.UserUpPwdResp{Empty: nil}, nil
}

// UserLoginByMb 用户手机登录
func (c *UserService) UserLoginByMb(ct context.Context, req *proto.UserLoginByMbReq) (*proto.UserLoginByMbResp, error) {
	var u models.User
	res := global.DB.Table("user").Where("username=?", req.Password).First(&u)
	if res.Error != nil {
		zap.S().Debug("登录失败")
		return nil, status.Errorf(codes.Unimplemented, "该手机号不存在，请先注册！！！")
	}

	if !utils.CheckPassword(req.Password, u.Password) {
		zap.S().Info("密码错误")
		return nil, status.Errorf(codes.Unimplemented, "密码错误！！！")
	}
	fmt.Println("登录成功")
	data := modelResponse(u)
	return &proto.UserLoginByMbResp{
		User: data,
		Code: 1,
	}, nil
}

// UserUpPhoto 用户上传头像
func (c *UserService) UserUpPhoto(ctx context.Context, req *proto.UserUpPhotoReq) (*proto.UserUpPhotoResp, error) {
	res := global.DB.Table("user").Where("id=?", req.Id).Update("user_photo =?", req.PhotoUrl)
	if res.Error != nil {
		return nil, status.Errorf(codes.Unimplemented, "上传失败!!!")
	}
	return &proto.UserUpPhotoResp{Empty: nil}, nil
}

// UserInFoList 用户信息列表展示
func (c *UserService) UserInFoList(ctx context.Context, req *proto.UserInFoListReq) (*proto.UserInFoListResp, error) {

	logs.Info("我进来了啊啊啊啊")
	var g []models.User
	//fmt.Println(req.PageSize)
	pageSize, offset, pages := ListFenYe(req.Page, req.PageSize)
	//fmt.Println(offset)
	res := global.DB.Table("user").Limit(int(pageSize)).Offset(offset).Find(&g)
	if res.Error != nil {
		return nil, status.Errorf(codes.Unimplemented, res.Error.Error())
	}
	var data []*proto.User

	for _, v := range g {
		data = append(data, modelResponse(v))
	}

	return &proto.UserInFoListResp{
		Total: int64(pages),
		User:  data,
	}, nil
}

// modelResponse 结构体转换
func modelResponse(u models.User) *proto.User {
	return &proto.User{
		Id:          u.Id,
		Username:    u.Username,
		Password:    u.Password,
		Email:       u.Email,
		Mobile:      u.Mobile,
		UserBalance: float32(u.UserBalance),
	}
}

// ListFenYe 列表分页
func ListFenYe(page, pageSz int64) (int64, int, float64) {
	//获取总数据
	count := 0
	global.DB.Raw("SELECT count(1) FROM user").Scan(&count)

	//每页展示多少条数据
	pageSize := pageSz
	//总页数
	pages := math.Ceil(float64(count) / float64(pageSize))

	//当前页
	nowPage := 1
	if page != 1 {
		nowPage = int(page)
	}
	//偏移量
	offset := (nowPage - 1) * int(pageSize)
	return pageSize, offset, pages
}
